﻿//#include"sys_inc.h"
#include "ff.h"
#include "ebook_api.h"
#include "ebook_init.h"
#include "ebook_util.h"
#include "db_format.h"
//#include "app_config.h"

#if LV_HOR_RES_MAX==240 && LV_VER_RES_MAX==320
const int EBOOK_VERSION = ((1) << 17) + (0);
#define LINES_PER_PAGE	13
//#define CHARS_PER_LINE	28
#elif LV_HOR_RES_MAX==128 && LV_VER_RES_MAX==160
const int EBOOK_VERSION = ((1) << 18) + (0);
#define LINES_PER_PAGE	9
//#define CHARS_PER_LINE	18	//22*7=154 < 160
#elif LV_HOR_RES_MAX==240 && LV_VER_RES_MAX==240
const int EBOOK_VERSION = ((1) << 19) + (0);
#define LINES_PER_PAGE	10
//#define CHARS_PER_LINE	28
#else
#error "ebook width and height not defined!"
#endif

#define LINEPX	(LV_HOR_RES_MAX-16)	//每行的像素
#define CHARSPACE	0			//字间距

#define is_english(c) (((c)>='a'&&(c)<='z')||((c)>='A'&&(c)<='Z'))
#define BE2LE(a)	((((a)>>8)&0xff)+(((a)&0xff)<<8))

extern WCHAR ff_covert_oem2uni(	/* Converted code, 0 means conversion error */
	WCHAR   oem,    /* Unicode character to be converted */
	WORD    cp      /* Code page for the conversion */

);

#ifdef WIN32
uint16_t g_get_word_width(uint32_t word)
{
	if (word < 0x80)
	{
		return 11;
	}
	else
	{
		return 16;
	}
}
#else
extern uint16_t g_get_word_width(uint32_t word);
#endif

uint32_t utf8_to_unicode(const uint8_t* txt, int len)
{
	uint32_t unicode = 0;
	switch (len)
	{
	case 0:
		assert(0);
		break;
	case 1:
		assert(0);
		unicode = txt[0] & 0x3f;
		break;
	case 2:
		unicode = (txt[0] & 0x1f);
		unicode = (unicode << 6) + (txt[1] & 0x3f);
		break;
	case 3:
		unicode = (txt[0] & 0x0f);
		unicode = (unicode << 6) + (txt[1] & 0x3f);
		unicode = (unicode << 6) + (txt[2] & 0x3f);
		break;
	case 4:
		unicode = (txt[0] & 0x07);
		unicode = (unicode << 6) + (txt[1] & 0x3f);
		unicode = (unicode << 6) + (txt[2] & 0x3f);
		unicode = (unicode << 6) + (txt[3] & 0x3f);
		break;
	case 5:
		unicode = (txt[0] & 0x03);
		unicode = (unicode << 6) + (txt[1] & 0x3f);
		unicode = (unicode << 6) + (txt[2] & 0x3f);
		unicode = (unicode << 6) + (txt[3] & 0x3f);
		unicode = (unicode << 6) + (txt[4] & 0x3f);
		break;
	case 6:
		unicode = (txt[0] & 0x01);
		unicode = (unicode << 6) + (txt[1] & 0x3f);
		unicode = (unicode << 6) + (txt[2] & 0x3f);
		unicode = (unicode << 6) + (txt[3] & 0x3f);
		unicode = (unicode << 6) + (txt[4] & 0x3f);
		unicode = (unicode << 6) + (txt[5] & 0x3f);
		break;
	default:
		assert(0);
		break;
	}
	return unicode;
}

uint32_t utf16_to_unicode(uint16_t word)
{
	uint32_t unicode = word & 0xffff;
	return unicode;
}

int get_char_pixel(uint16_t ch)
{
	return g_get_word_width(ch);
}

WCHAR ff_oem2uni(WCHAR oem, WORD cp);	/* OEM code to Unicode conversion */
WCHAR ff_uni2oem(DWORD uni, WORD cp);	/* Unicode to OEM code conversion */

int get_ansi_pixel(const uint8_t* txt, int len)
{
	uint32_t unicodeKey = 0;
	assert(len == 2);
	unicodeKey = ff_oem2uni((txt[0] << 8) + txt[1], CodePage);
	return g_get_word_width(unicodeKey);
}

int get_utf8_pixel(const uint8_t* txt, int len)
{
	uint32_t unicodeKey = utf8_to_unicode(txt, len);
	return g_get_word_width(unicodeKey);
}

int get_utf16_pixel(uint16_t word)
{
	uint32_t unicodeKey = utf16_to_unicode(word);
	return g_get_word_width(unicodeKey);
}

int is_blank_line(const uint8_t* txt, int len)
{
	if (len == 0)
	{
		assert(0);
	}
	else if (len == 1)
	{
		return txt[0] == '\n';
	}
	else if (len == 2)
	{
		return txt[0] == '\r' && txt[1] == '\n';
	}
	else
	{
		assert(txt[0] != '\n');
		assert(!(txt[0] == '\r' && txt[1] == '\n'));
	}

	return 0;
}

int is_blank_line16LE(const uint16_t* p, int len)
{
	if (len == 0)
	{
		assert(0);
	}
	else if (len == 1)
	{
		return p[0] == 0x000A;
	}
	else if (len == 2)
	{
		return p[0] == 0x000D && p[1] == 0x000A;
	}
	else
	{
		assert(p[0] != 0x000A);
		assert(!(p[0] == 0x000D && p[1] == 0x000A));
	}

	return 0;
}

int is_blank_line16BE(const uint16_t* p, int len)
{
	if (len == 0)
	{
		assert(0);
	}
	else if (len == 1)
	{
		return p[0] == 0x0A00;
	}
	else if (len == 2)
	{
		return p[0] == 0x0D00 && p[1] == 0x0A00;
	}
	else
	{
		assert(p[0] != 0x0A00);
		assert(!(p[0] == 0x0D00 && p[1] == 0x0A00));
	}

	return 0;
}

int ansi_get_word(const uint8_t* txt, int len, int* used)//返回used是消耗掉buff的长度，函数返回值字符像素宽度
{
	int i;
	int retPX = 0;
	int charPX = 0;

	if (is_english(txt[0]))
	{
		retPX = get_char_pixel(txt[0]);

		for (i = 1; i < len; i++)
		{
			if (is_english(txt[i]))
			{
				charPX = get_char_pixel(txt[i]);
				if (retPX + CHARSPACE + charPX > LINEPX)
				{
					*used = i - 1;
					return retPX;
				}
				else
				{
					retPX += CHARSPACE + charPX;
				}
			}
			else
			{
				break;
			}
		}
		*used = i;
		return retPX;
	}
	if (txt[0] < 0x80)
	{
		*used = 1;
		retPX = get_char_pixel(txt[0]);
		return retPX;
	}
	else
	{
		*used = 2;
		retPX = get_ansi_pixel(txt, 2);
		return retPX;
	}
}

int ansi_one_line(const uint8_t* txt, int len)//返回一行的长度
{
	int i = 0;
	int used = 0;
	int linePX = 0;
	int showPX = 0;

	for (i = 0; i < len && linePX < LINEPX; )
	{
		if (txt[i] == '\n')
		{
			i += 1;
			break;
		}
		else if (txt[i] == '\r')
		{
			i += 1;
		}
		else
		{
			showPX = ansi_get_word(txt + i, len - i, &used);

			if (linePX + CHARSPACE + showPX > LINEPX)
			{
				if (i == 0)
				{
					assert(0);
					//i = CHARS_PER_LINE;
				}
				break;
			}
			else
			{
				linePX += CHARSPACE + showPX;
				i += used;
			}
		}
	}
	return i;
}

int ansi_page_len(const uint8_t* txt, int len)
{
	//整屏可显示14行，每行28个英文字符，单词不可以回行。
	int row = 0;
	int i = 0;
	while (i < len)
	{
		int ret = ansi_one_line(txt + i, len - i);
		if (is_blank_line(&txt[i], ret))
		{
			i += ret;
		}
		else
		{
			i += ret;
			row++;
			if (row >= LINES_PER_PAGE)
			{
				return i;
			}
		}
	}
	return len;
}

int utf8_get_word(const uint8_t* txt, int len, int* used)//返回used是消耗掉buff的长度，函数返回值字符像素宽度
{
	int i;
	int retPX = 0;
	int charPX = 0;

	if (is_english(txt[0]))
	{
		retPX = get_char_pixel(txt[0]);

		for (i = 1; i < len; i++)
		{
			if (is_english(txt[i]))
			{
				charPX = get_char_pixel(txt[i]);
				if (retPX + CHARSPACE + charPX > LINEPX)
				{
					*used = i - 1;
					return retPX;
				}
				else
				{
					retPX += CHARSPACE + charPX;
				}
			}
			else
			{
				break;
			}
		}
		*used = i;
		return retPX;
	}
	if (txt[0] < 0x80)
	{
		*used = 1;
		retPX = get_char_pixel(txt[0]);
		return retPX;
	}
	else if ((txt[0] & 0xC0) == 0x80)//	10xxxxxx
	{
		*used = 1;
		assert(0);
		retPX = get_utf8_pixel(txt, 1);
		return retPX;
	}
	else if ((txt[0] & 0xE0) == 0xC0)//	110xxxxx 10xxxxxx
	{
		*used = 2;
		retPX = get_utf8_pixel(txt, 2);
		return retPX;
	}
	else if ((txt[0] & 0xF0) == 0xE0)//	1110xxxx 10xxxxxx 10xxxxxx
	{
		*used = 3;
		retPX = get_utf8_pixel(txt, 3);
		return retPX;
	}
	else if ((txt[0] & 0xF8) == 0xF0)//	11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
	{
		*used = 4;
		retPX = get_utf8_pixel(txt, 4);
		return retPX;
	}
	else if ((txt[0] & 0xFC) == 0xF8)//	111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
	{
		*used = 5;
		retPX = get_utf8_pixel(txt, 5);
		return retPX;
	}
	else if ((txt[0] & 0xFC) == 0xF8)//	1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
	{
		*used = 6;
		retPX = get_utf8_pixel(txt, 6);
		return retPX;
	}
	else
	{
		assert(0);
		*used = 1;
		retPX = get_utf8_pixel(txt, 1);
		return retPX;
	}
}

int utf8_one_line(const uint8_t* txt, int len)//返回一行的长度
{
	int i = 0;
	int used = 0;
	int linePX = 0;
	int showPX = 0;

	for (i = 0; i < len && linePX < LINEPX; )
	{
		if (txt[i] == '\n')
		{
			i += 1;
			break;
		}
		else if (txt[i] == '\r')
		{
			i += 1;
		}
		else
		{
			showPX = utf8_get_word(txt + i, len - i, &used);

			if (linePX + CHARSPACE + showPX > LINEPX)
			{
				if (i == 0)
				{
					assert(0);
					//i = CHARS_PER_LINE;
				}
				break;
			}
			else
			{
				linePX += CHARSPACE + showPX;
				i += used;
			}
		}
	}
	return i;
}

int utf8_page_len(const uint8_t* txt, int len)
{
	//整屏可显示14行，每行28个英文字符，单词不可以回行。
	int row = 0;
	int i = 0;
	while (i < len)
	{
		int ret = utf8_one_line(txt + i, len - i);
		if (is_blank_line(&txt[i], ret))
		{
			i += ret;
		}
		else
		{
			i += ret;
			row++;
			if (row >= LINES_PER_PAGE)
			{
				return i;
			}
		}
	}
	return len;
}

int utf16le_get_word(const uint16_t* p, int len, int* used)//返回used是消耗掉buff的长度，函数返回值字符像素宽度
{
	int i;
	int retPX = 0;
	int charPX = 0;

	if (is_english(p[0]))
	{
		retPX = get_char_pixel(p[0]);

		for (i = 1; i < len; i++)
		{
			if (is_english(p[i]))
			{
				charPX = get_char_pixel(p[i]);
				if (retPX + CHARSPACE + charPX > LINEPX)
				{
					*used = i - 1;
					return retPX;
				}
				else
				{
					retPX += CHARSPACE + charPX;
				}
			}
			else
			{
				break;
			}
		}
		*used = i;
		return retPX;
	}
	if (p[0] < 0x0080)
	{
		*used = 1;
		retPX = get_char_pixel(p[0]);
		return retPX;
	}
	else
	{
		*used = 1;
		retPX = get_utf16_pixel(p[0]);
		return retPX;
	}
}

int utf16le_one_line(const uint16_t* p, int len)//返回一行的长度
{
	int i = 0;
	int used = 0;
	int linePX = 0;
	int showPX = 0;

	for (i = 0; i < len && linePX < LINEPX; )
	{
		if (p[i] == 0x000A)
		{
			i += 1;
			break;
		}
		else if (p[i] == 0x000D)
		{
			i += 1;
		}
		else
		{
			showPX = utf16le_get_word(p + i, len - i, &used);

			if (linePX + CHARSPACE + showPX > LINEPX)
			{
				if (i == 0)
				{
					assert(0);
					//i = CHARS_PER_LINE;
				}
				break;
			}
			else
			{
				linePX += CHARSPACE + showPX;
				i += used;
			}
		}
	}
	return i;
}

int utf16le_page_len(const uint16_t* p, int len)
{
	//整屏可显示14行，每行28个英文字符，单词不可以回行。
	int row = 0;
	int i = 0;
	while (i < len)
	{
		int ret = utf16le_one_line(p + i, len - i);
		if (is_blank_line16LE(&p[i], ret))
		{
			i += ret;
		}
		else
		{
			i += ret;
			row++;
			if (row >= LINES_PER_PAGE)
			{
				return i;
			}
		}
	}
	return len;
}

int utf16be_get_word(const uint16_t* p, int len, int* used)//返回used是消耗掉buff的长度，函数返回值字符像素宽度
{
	int i;
	int retPX = 0;
	int charPX = 0;

	uint16_t tmp = BE2LE(p[0]);

	if (is_english(tmp))
	{
		retPX = get_char_pixel(tmp);

		for (i = 1; i < len; i++)
		{
			uint16_t le = BE2LE(p[i]);

			if (is_english(le))
			{
				charPX = get_char_pixel(le);
				if (retPX + CHARSPACE + charPX > LINEPX)
				{
					*used = i - 1;
					return retPX;
				}
				else
				{
					retPX += CHARSPACE + charPX;
				}
			}
			else
			{
				break;
			}
		}
		*used = i;
		return retPX;
	}
	if (tmp < 0x0080)
	{
		*used = 1;
		retPX = get_char_pixel(tmp);
		return retPX;
	}
	else
	{
		*used = 1;
		retPX = get_utf16_pixel(tmp);
		return retPX;
	}
}

int utf16be_one_line(const uint16_t* p, int len)//返回一行的长度
{
	int i = 0;
	int used = 0;
	int linePX = 0;
	int showPX = 0;

	for (i = 0; i < len && linePX < LINEPX; )
	{
		if (BE2LE(p[i]) == 0x000A)
		{
			i += 1;
			break;
		}
		else if (BE2LE(p[i]) == 0x000D)
		{
			i += 1;
		}
		else
		{
			showPX = utf16be_get_word(p + i, len - i, &used);

			if (linePX + CHARSPACE + showPX > LINEPX)
			{
				if (i == 0)
				{
					assert(0);
					//i = CHARS_PER_LINE;
				}
				break;
			}
			else
			{
				linePX += CHARSPACE + showPX;
				i += used;
			}
		}
	}
	return i;
}

int utf16be_page_len(const uint16_t* p, int len)
{
	//整屏可显示14行，每行28个英文字符，单词不可以回行。
	int row = 0;
	int i = 0;
	while (i < len)
	{
		int ret = utf16be_one_line(p + i, len - i);
		if (is_blank_line16BE(&p[i], ret))
		{
			i += ret;
		}
		else
		{
			i += ret;
			row++;
			if (row >= LINES_PER_PAGE)
			{
				return i;
			}
		}
	}
	return len;
}

int calculate_page_len(const uint8_t* txt, int len)
{
	switch (hebook->format)
	{
	case ASCII_FORMAT:
	case ANSI_FORMAT:
		return ansi_page_len(txt, len);
	case UTF_8_NOBOM_FORMAT:
	case UTF_8_BOM_FORMAT:
		return utf8_page_len(txt, len);
	case UTF_16_L_ENDIAN_FORMAT:
		return utf16le_page_len((uint16_t*)txt, len / 2) * 2;
	case UTF_16_B_ENDIAN_FORMAT:
		return utf16be_page_len((uint16_t*)txt, len / 2) * 2;
	case UTF_32_L_ENDIAN_FORMAT:
	case UTF_32_B_ENDIAN_FORMAT:
		return -1;
	default:
		return -1;
	}
}

int get_txt_info(void)
{
	//获取txt文件信息，编码格式、文件大小等
	int res;
	unsigned int br;
	hebook->f_size = (int)f_size(hebook->f_txt);
	f_lseek(hebook->f_txt, 0);
	res = f_read(hebook->f_txt, &hebook->txt_ui, TXT_SIZE, &br);
	if (res == FR_OK)
	{
		hebook->format = db_check_format(hebook->txt_ui, br, hebook->default_format);
		if (ERROR_FORMAT == hebook->format)
		{
			return -1;
		}
	}
	return 0;
}

int calculate_page_offset(int offset[2])
{
	//return 0:		构建索引文件单步OK
	//return -1:	构建索引文件出错
	//return -2:	txt文件结束，本次单步无数据

	int res;
	unsigned br = 0;
	int page_len;

	f_lseek(hebook->f_txt, offset[0]);
	res = f_read(hebook->f_txt, hebook->txt_index, TXT_SIZE, &br);
	if (res != FR_OK)
	{
		return -1;
	}
	if (br == 0)
	{
		return -2;
	}

	page_len = calculate_page_len(hebook->txt_index, br);
	if (page_len == -1)
	{
		return -1;
	}

	offset[1] = offset[0] + page_len;

	return 0;
}

int save_index(int offset[2])
{
	int res;
	unsigned br = 0;
	long long last = sizeof(INDEX_HEAD) + hebook->pages * sizeof(int);
	f_lseek(hebook->f_idx, last);
	res = f_write(hebook->f_idx, offset, sizeof(int) * 2, &br);
	if (res == FR_OK && br == sizeof(int) * 2)
	{
		hebook->pages++;
		return res;
	}
	else
	{
		return -1;
	}
}

int convert_page_to_ui(uint8_t* from, uint8_t* to)
{
	//整屏可显示14行，每行28个英文字符，单词不可以回行。
	char tmp[256];
	int len = strlen((char*)from);
	int i = 0;
	to[0] = 0;

	while (i < len)
	{
		int ret = utf8_one_line(from + i, len - i);
		if (is_blank_line(&from[i], ret))
		{
			i += ret;
		}
		else
		{
			if (ret < 256)
			{
				memcpy(tmp, &from[i], ret);
				tmp[ret] = 0;
				strcat((char*)to, tmp);
				if (tmp[ret - 1] != '\n')
				{
					strcat((char*)to, "\r\n");
				}
				i += ret;
			}
			else
			{
				memcpy(tmp, &from[i], 256 - 1);
				tmp[256 - 1] = 0;
				strcat((char*)to, tmp);
				i += ret;
			}
		}
	}
	return 0;
}

int convert_page(int len)
{
	switch (hebook->format)
	{
	case ASCII_FORMAT:
	case ANSI_FORMAT:
	{
		int ret = db_gb2312_to_utf8(hebook->txt_ui, len, hebook->convert_txt, TXT_SIZE);
		hebook->convert_txt[ret] = 0;
		if (ret == 0)
		{
			return -1;
		}
	}
	break;

	case UTF_8_NOBOM_FORMAT:
	case UTF_8_BOM_FORMAT:
		strcpy((char*)hebook->convert_txt, (char*)hebook->txt_ui);
		break;

	case UTF_16_L_ENDIAN_FORMAT:
	{
		int ret = UTF_16LE_to_utf8(hebook->txt_ui, len, hebook->convert_txt, TXT_SIZE);
		hebook->convert_txt[ret] = 0;
		if (ret == 0)
		{
			return -1;
		}
	}
	break;

	case UTF_16_B_ENDIAN_FORMAT:
	{
		int ret = UTF_16BE_to_utf8(hebook->txt_ui, len, hebook->convert_txt, TXT_SIZE);
		hebook->convert_txt[ret] = 0;
		if (ret == 0)
		{
			return -1;
		}
	}
	break;

	case UTF_32_L_ENDIAN_FORMAT:
	case UTF_32_B_ENDIAN_FORMAT:
		return -1;

	default:
		return -1;
	}

	return convert_page_to_ui(hebook->convert_txt, hebook->utf8_txt);
}

int get_page_(void)
{
	int res;
	unsigned br = 0;
	int offset[2];
	long long last;
	int len;

	last = sizeof(INDEX_HEAD) + hebook->page * sizeof(int);
	f_lseek(hebook->f_idx, last);
	res = f_read(hebook->f_idx, offset, sizeof(offset), &br);
	if (res != FR_OK)
	{
		return -1;
	}
	if (br != sizeof(offset))
	{
		return -1;
	}

	len = offset[1] - offset[0];
	if (len >= TXT_SIZE)
	{
		return -1;
	}

	f_lseek(hebook->f_txt, offset[0]);
	res = f_read(hebook->f_txt, hebook->txt_ui, len, &br);
	if (res != FR_OK)
	{
		return -1;
	}
	if ((int)br != len)
	{
		return -1;
	}

	hebook->txt_ui[len] = 0;

	return len;
}

int get_page(void)
{
	int res;

	if (hebook->building)
	{
		//assert(hebook->q_to_task != 0);
		//assert(hebook->q_fm_task != 0);
		//assert(hebook->task != 0);
		int msg = hebook->page;
		res = OAL_queue_send(&hebook->q_to_task, &msg, OAL_WAIT_FOREVER);
		if (res == OAL_SUCCESS)
		{
			res = OAL_queue_recv(&hebook->q_fm_task, &msg, OAL_WAIT_FOREVER);
			if (res == OAL_SUCCESS)
			{
				if (msg == -1)
				{
					return -1;
				}
				else
				{
					//assert(msg == hebook->page);
					return convert_page(msg);
				}
			}
			else
			{
				return -1;
			}
		}
		else
		{
			return -1;
		}
	}
	else
	{
		res = get_page_();
		if (res == -1)
		{
			return res;
		}
		return convert_page(res);
	}
}

int get_last_offset(void)
{
	int res;
	unsigned br = 0;
	int offset;
	long long last = f_size(hebook->f_idx) - sizeof(int);
	//assert(sizeof(INDEX_HEAD) + head.pages*sizeof(int) == last);

	f_lseek(hebook->f_idx, last);
	res = f_read(hebook->f_idx, &offset, sizeof(int), &br);
	if (res != FR_OK)
	{
		return -1;
	}
	if (br != sizeof(int))
	{
		return -1;
	}
	return offset;
}

void* task_build_index(void* prm)
{
	int offset[2] = { 0,0 };
	prm = prm;

	offset[0] = get_last_offset();

	if (offset[0] == -1)
	{
		hebook->building = -1;
		hebook->cb(-1);
	}

	for (;;)
	{
		int msg;
		if (OAL_SUCCESS == OAL_queue_recv(&hebook->q_to_task, &msg, 0))
		{
			if (msg == -1)
			{
				break;
			}
			else
			{
				int send = get_page_();
				OAL_queue_send(&hebook->q_fm_task, &send, OAL_WAIT_FOREVER);
				//assert(OAL_SUCCESS == res);
			}
		}
		else
		{
			if (hebook->building == 1)
			{
				int res = calculate_page_offset(offset);
				switch (res)
				{
				case 0:	//构建索引文件单步OK，保存index信息
					res = save_index(offset);
					offset[0] = offset[1];
					if (res == FR_OK)
					{
						hebook->cb(hebook->pages);
					}
					else
					{
						hebook->building = -1;
						hebook->cb(-1);
					}
					break;
				case -1:	//构建索引文件出错，不保存index信息
					hebook->building = -1;
					hebook->cb(-1);
					break;
				case -2:	//txt文件结束，本次单步无数据，不保存index信息
					hebook->building = 0;
					hebook->cb(-2);
					break;
				default:
					assert(0);	//not arrived
					break;
				}
			}
			OAL_sleep(10);
		}
	}
	return 0;
}

int create_task(void)
{
	int res;
	OAL_QUEUE_POOL pool = { sizeof(int) * 1 };
	res = OAL_queue_create(&hebook->q_to_task, (char*)"to task", sizeof(int), &pool);
	if (res != OAL_SUCCESS)
	{
		hebook->q_to_task = (void*)0;
		return -1;
	}
	res = OAL_queue_create(&hebook->q_fm_task, (char*)"from task", sizeof(int), &pool);
	if (res != OAL_SUCCESS)
	{
		res = OAL_queue_delete(&hebook->q_to_task);
		hebook->q_to_task = (void*)0;
		hebook->q_fm_task = (void*)0;
		return -1;
	}

	hebook->task = OAL_thread_create(task_build_index, 0, (char*)"build index", OAL_THREAD_PRIORITY_LOW, 512);
	if (hebook->task == 0)
	{
		res = OAL_queue_delete(&hebook->q_to_task);
		res = OAL_queue_delete(&hebook->q_fm_task);
		hebook->q_to_task = (void*)0;
		hebook->q_fm_task = (void*)0;
		return -1;
	}

	return 0;
}

int close_task(void)
{
	int msg = -1;
	OAL_queue_send(&hebook->q_to_task, &msg, OAL_WAIT_FOREVER);
	OAL_thread_join(hebook->task);
	hebook->task = (void*)0;
	OAL_queue_delete(&hebook->q_to_task);
	OAL_queue_delete(&hebook->q_fm_task);
	hebook->q_to_task = (void*)0;
	hebook->q_fm_task = (void*)0;
	return 0;
}

int fnamecmp(char* path1, char* path2)
{
	char* p1 = path1 + strlen(path1) - 5;
	char* p2 = path2 + strlen(path2) - 5;

	while (p1 > path1)
	{
		char c = *(p1 - 1);
		if (c == '/' || c == '\\') break;
		else --p1;
	}
	while (p2 > path2)
	{
		char c = *(p2 - 1);
		if (c == '/' || c == '\\') break;
		else --p2;
	}
	return strcmp(p1, p2);
}


FRESULT ffopen(FIL** fp, const char* path, uint8_t mode)
{
	FRESULT res;

	assert(*fp == 0);
	*fp = (FIL*)OAL_calloc(1, sizeof(FIL));
	if (0 == *fp)
	{
		return FR_INT_ERR;
	}

	res = f_open(*fp, path, mode);

	if (FR_OK != res)
	{
		OAL_free(*fp);
		*fp = 0;
	}

	return res;
}

FRESULT ffclose(FIL** fp)
{
	if (*fp)
	{
		FRESULT res = f_close(*fp);
		OAL_free(*fp);
		*fp = 0;
		return res;
	}
	return FR_OK;
}
